package com.atwisdom.star.core.bsl.planner.Impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.util.TypeUtils;
import com.atwisdom.star.common.vo.ModelType;
import com.atwisdom.star.core.bsl.planner.MrpBslService;
import com.atwisdom.star.core.bsl.planner.entity.*;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.logic.LogicInstance;
import com.atwisdom.star.core.dsl.modelClass.hier.HierInstanceDslService;
import com.atwisdom.star.core.dsl.modelClass.logic.Impl.LogicInstanceDslServiceImpl;
import com.atwisdom.star.exception.pojo.BusinessException;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

@Data
@Service
public class MrpBslServiceImpl implements MrpBslService {
    @Autowired
    private LogicInstanceDslServiceImpl logicInstanceDslService;
    @Autowired
    private HierInstanceDslService hierInstanceDslService;
    @Autowired
    private ProductBomBslServiceImpl productBomBslService;
    @Autowired
    private MaterialBslServiceImpl materialBslService;


    //销售订单按背番、发货日期分组发货量汇总数据列表
    private List<SaleOrderSummary> saleOrderSummaryList = new ArrayList<>();

    //生产计划订单
    private List<ProductionPlanOrder> productionPlanOrders = new ArrayList<>();
    //生产计划订单明细
    private List<ProductionPlanOrderSub> productionPlanOrderSubs = new ArrayList<>();
    //采购订单
    private List<PurchasePlanOrder> purchasePlanOrders = new ArrayList<>();
    //采购订单明细
    List<PurchasePlanOrderSub> purchasePlanOrderSubs = new ArrayList<>();
    //委外计划订单
    private List<OutsourcingPlanOrder> outsourcingPlanOrders = new ArrayList<>();
    //委外计划订单明细
    private List<OutsourcingPlanOrderSub> outsourcingPlanOrderSubs = new ArrayList<>();

    /**
     * 合并map
     *
     * @param firstMap  第一个map
     * @param secondMap 第二个map
     * @return
     */
    @Override
    public void mergedMap(Map<String, Double> firstMap, Map<String, Double> secondMap) {
        for (Map.Entry<String, Double> entry : secondMap.entrySet()) {
            String key = entry.getKey();
            Double value = entry.getValue();

            if (firstMap.containsKey(key)) {
                firstMap.put(key, firstMap.get(key) + value);
            } else {
                firstMap.put(key, value);
            }
        }
    }

    /**
     * 返回采购订单数量
     *
     * @return
     */
    @Override
    public Map<String, Double> fetchProductionPlanOrder(String condition) {
        this.productionPlanOrders = new ArrayList<>();
        this.productionPlanOrderSubs = new ArrayList<>();
        List<JSONObject> productionOrderList = this.logicInstanceDslService.query(condition, "ProductionPlanOrder", null);
        for (JSONObject jsonObject : productionOrderList) {
            int orderId = jsonObject.getInteger("id");
            JSONObject mainValues = jsonObject.getJSONObject("values");
            String orderCode = mainValues.getString("code");
            String orderName = mainValues.getString("name");
            String orderType = mainValues.getString("orderType");
            Long materialId = mainValues.getLong("material_id");
            String materialPCode = mainValues.getString("material_pcode");
            String materialBCode = mainValues.getString("material_bcode");
            String materialSpec = mainValues.getString("material_spec");
            String materialModel = mainValues.getString("material_model");
            Date planStartDate = mainValues.getDate("startDate");
            Date planEndDate = mainValues.getDate("endDate");
            Integer quantity = mainValues.getInteger("quantity") == null ? 0 : mainValues.getInteger("quantity");
            Double workHours = mainValues.getDouble("workHours");
            Boolean isLock = mainValues.getBoolean("isLock");
            Boolean isCreate = mainValues.getBoolean("isCreate");

            ProductionPlanOrder productionPlanOrder = new ProductionPlanOrder();
            productionPlanOrder.setId(orderId);
            productionPlanOrder.setCode(orderCode);
            productionPlanOrder.setName(orderName);
            productionPlanOrder.setOrderType(orderType);
            productionPlanOrder.setMaterialId(materialId);
            productionPlanOrder.setMaterialPCode(materialPCode);
            productionPlanOrder.setMaterialBCode(materialBCode);
            productionPlanOrder.setMaterialModel(materialModel);
            productionPlanOrder.setMaterialSpec(materialSpec);
            productionPlanOrder.setStartDate(planStartDate);
            productionPlanOrder.setEndDate(planEndDate);
            productionPlanOrder.setQuantity(quantity);
            productionPlanOrder.setWorkHours(workHours);
            productionPlanOrder.setLocked(isLock);
            productionPlanOrder.setCreated(isCreate);

            JSONObject hier = jsonObject.getJSONObject("hier");
            JSONArray content = hier.getJSONArray("content");
            productionPlanOrder.setProductionPlanOrderSubList(new ArrayList<>());

            for (int i = 0; i < content.size(); i++) {
                JSONObject contentJson = (JSONObject) content.get(i);
                String nodeId = contentJson.getString("nodeId");
                if (nodeId.equalsIgnoreCase("root")) {
                    continue;
                }
                JSONObject values = contentJson.getJSONObject("values");
                Long materialIdSub = values.getLong("material_id");
                String materialPCodeSub = values.getString("material_pcode");
                String materialBCodeSub = values.getString("material_bcode");
                String materialSpecSub = values.getString("material_spec");
                String materialModelSub = values.getString("material_model");
                String subTypeSub = values.getString("subType");
                Integer quantitySub = values.getInteger("quantity") == null ? 0 : values.getInteger("quantity");

                ProductionPlanOrderSub productionPlanOrderSub = new ProductionPlanOrderSub();
                productionPlanOrderSub.setPlanId(orderId);
                productionPlanOrderSub.setMaterialId(materialIdSub);
                productionPlanOrderSub.setProductBCode(materialPCode);
                productionPlanOrderSub.setMaterialPCode(materialPCodeSub);
                productionPlanOrderSub.setMaterialBCode(materialBCodeSub);
                productionPlanOrderSub.setMaterialModel(materialModelSub);
                productionPlanOrderSub.setMaterialSpec(materialSpecSub);
                productionPlanOrderSub.setSubType(subTypeSub);
                productionPlanOrderSub.setQuantity(quantitySub);
                productionPlanOrder.getProductionPlanOrderSubList().add(productionPlanOrderSub);

                //明细合并
                this.productionPlanOrderSubs.add(productionPlanOrderSub);
            }
            productionPlanOrders.add(productionPlanOrder);
        }
        Map<String, Double> productionMap = productionPlanOrders.stream().collect(Collectors.groupingBy(ProductionPlanOrder::getMaterialBCode, Collectors.summingDouble(ProductionPlanOrder::getQuantity)));
        return productionMap;
    }


    /**
     * 获取生产工单未完工数据
     *
     * @param condition 查询条件
     * @param className 类名
     * @return 返回结果
     */
    @Override
    public Map<String, Double> fetchWorkOrder(String condition, String className) {
        List<JSONObject> workOrderList = this.logicInstanceDslService.query(condition, className, null);
        List<WorkOrder> workOrders = new ArrayList<>();
        for (JSONObject jsonObject : workOrderList) {
            int orderId = jsonObject.getInteger("id");
            JSONObject mainValues = jsonObject.getJSONObject("values");
            String orderNumber = mainValues.getString("orderNumber");
            String orderType = mainValues.getString("orderType");
            Long materialId = mainValues.getLong("material_id");
            String materialPCode = mainValues.getString("material_pcode");
            String materialBCode = mainValues.getString("material_bcode");
            String materialSpec = mainValues.getString("material_spec");
            String materialModel = mainValues.getString("material_model");
            Date planStartDate = mainValues.getDate("startDate");
            Date planEndDate = mainValues.getDate("endDate");
            Integer quantity = mainValues.getInteger("quantity") == null ? 0 : mainValues.getInteger("quantity");
            String status = mainValues.getString("status");

            WorkOrder workOrder = new WorkOrder();
            workOrder.setId(orderId);
            workOrder.setOrderNumber(orderNumber);
            workOrder.setOrderType(orderType);
            workOrder.setMaterialId(materialId);
            workOrder.setMaterialPCode(materialPCode);
            workOrder.setMaterialBCode(materialBCode);
            workOrder.setMaterialModel(materialModel);
            workOrder.setMaterialSpec(materialSpec);
            workOrder.setStartDate(planStartDate);
            workOrder.setEndDate(planEndDate);
            workOrder.setQuantity(quantity);
            workOrder.setStatus(status);
            workOrders.add(workOrder);
        }
        Map<String, Double> workOrderMap = workOrders.stream().collect(Collectors.groupingBy(WorkOrder::getMaterialBCode, Collectors.summingDouble(WorkOrder::getQuantity)));
        return workOrderMap;
    }

    /**
     * 获取生产工单未完工数据
     *
     * @param condition 查询条件
     * @param className 类名
     * @return 返回结果
     */
    @Override
    public Map<String, Double> fetchWorkReport(String condition, String className) {
        List<HierInstance> workReportList = this.hierInstanceDslService.query(ModelType.Logic.getCode(), className, condition);

        List<WorkReport> workReports = new ArrayList<>();
        for (HierInstance hIns : workReportList) {
            JSONObject mainValues = hIns.getValues();
            String materialPCode = mainValues.getString("material_pcode");
            String materialBCode = mainValues.getString("material_bcode");
            Integer workReportNumber = mainValues.getInteger("workReportNumber") == null ? 0 : mainValues.getInteger("workReportNumber");
            Integer poorNumber = mainValues.getInteger("poorNumber") == null ? 0 : mainValues.getInteger("poorNumber");
            String status = mainValues.getString("status");

            WorkReport workReport = new WorkReport();
            workReport.setMaterialPCode(materialPCode);
            workReport.setMaterialBCode(materialBCode);
            workReport.setWorkReportNumber(workReportNumber);
            workReport.setPoorNumber(poorNumber);
            workReports.add(workReport);
        }
        Map<String, Double> workReportMap = workReports.stream().collect(Collectors.groupingBy(WorkReport::getMaterialBCode, Collectors.summingDouble(WorkReport::getQuantity)));
        return workReportMap;
    }

    /**
     * 获取生产返修报工单数量统
     *
     * @param condition 查询条件
     * @param className 类名
     * @return 返回结果
     */
    @Override
    public Map<String, Double> fetchRepairWorkReport(String condition, String className) {
        List<JSONObject> repairWorkOrderList = this.logicInstanceDslService.query(condition, className, null);
        List<WorkOrder> workOrders = new ArrayList<>();
        for (JSONObject jsonObject : repairWorkOrderList) {
            JSONObject mainValues = jsonObject.getJSONObject("values");
            String materialPCode = mainValues.getString("material_pcode");
            String materialBCode = mainValues.getString("material_bcode");
            Integer planRepairQuantity = mainValues.getInteger("quantity") == null ? 0 : mainValues.getInteger("quantity");
            Integer repairQuantity = mainValues.getInteger("repairQuantity") == null ? 0 : mainValues.getInteger("repairQuantity");
            Integer poorQuantity = mainValues.getInteger("poorQuantity") == null ? 0 : mainValues.getInteger("poorQuantity");
            Integer quantity = planRepairQuantity - repairQuantity - poorQuantity;
            WorkOrder workOrder = new WorkOrder();
            workOrder.setMaterialPCode(materialPCode);
            workOrder.setMaterialBCode(materialBCode);
            workOrder.setQuantity(quantity);
            workOrders.add(workOrder);
        }
        Map<String, Double> repairWorkOrderMap = workOrders.stream().collect(Collectors.groupingBy(WorkOrder::getMaterialBCode, Collectors.summingDouble(WorkOrder::getQuantity)));
        return repairWorkOrderMap;
    }

    /**
     * 获取销售返修单计划数量统计
     *
     * @param condition     查询条件
     * @param hierCondition 明细查询条件
     * @param className     类名
     * @return 返回结果
     */
    @Override
    public Map<String, Double> fetchSaleRepairWorkOrder(String condition, String hierCondition, String className) {
        List<LogicInstance> logicInstances = this.logicInstanceDslService.fetchInstanceList(condition, className, null);
        List<String> containerIds = logicInstances.stream().map(LogicInstance::getId).map(m -> m + "").collect(toList());
        if (CollectionUtil.isEmpty(containerIds)) {
            return new HashMap<>();
        }
        String tempIds = String.join(",", containerIds);
        hierCondition = hierCondition + " and containerId in (" + tempIds + ")";
        List<HierInstance> saleRepairWorkOrderList = this.hierInstanceDslService.query(ModelType.Logic.getCode(), className, hierCondition);
        List<WorkOrder> workOrders = new ArrayList<>();
        for (HierInstance hIns : saleRepairWorkOrderList) {
            JSONObject mainValues = hIns.getValues();
            String materialPCode = mainValues.getString("material_pcode");
            String materialBCode = mainValues.getString("material_bcode");
            Integer quantity = mainValues.getInteger("quantity") == null ? 0 : mainValues.getInteger("quantity");
            WorkOrder workOrder = new WorkOrder();
            workOrder.setMaterialPCode(materialPCode);
            workOrder.setMaterialBCode(materialBCode);
            workOrder.setQuantity(quantity);
            workOrders.add(workOrder);
        }
        Map<String, Double> saleRepairWorkOrderMap = workOrders.stream().collect(Collectors.groupingBy(WorkOrder::getMaterialBCode, Collectors.summingDouble(WorkOrder::getQuantity)));
        return saleRepairWorkOrderMap;
    }

    /**
     * 获取销售返修单计划数量统计
     *
     * @param condition     查询条件
     * @param hierCondition 明细查询条件
     * @param className     类名
     * @return 返回结果
     */
    @Override
    public Map<String, Double> fetchSaleRepairWorkReport(String condition, String hierCondition, String className) {
        List<LogicInstance> logicInstances = this.logicInstanceDslService.fetchInstanceList(condition, className, null);
        List<String> containerIds = logicInstances.stream().map(LogicInstance::getId).map(m -> m + "").collect(toList());
        if (CollectionUtil.isEmpty(containerIds)) {
            return new HashMap<>();
        }
        String tempIds = String.join(",", containerIds);
        hierCondition = hierCondition + " and containerId in (" + tempIds + ")";
        List<HierInstance> saleRepairWorkReportList = this.hierInstanceDslService.query(ModelType.Logic.getCode(), className, hierCondition);
        List<WorkReport> workReports = new ArrayList<>();
        for (HierInstance hIns : saleRepairWorkReportList) {
            JSONObject mainValues = hIns.getValues();
            String materialPCode = mainValues.getString("material_pcode");
            String materialBCode = mainValues.getString("material_bcode");
            Integer workReportNumber = mainValues.getInteger("repairQuantity") == null ? 0 : mainValues.getInteger("repairQuantity");
            Integer poorNumber = mainValues.getInteger("poorNumber") == null ? 0 : mainValues.getInteger("poorNumber");
            WorkReport workReport = new WorkReport();
            workReport.setMaterialPCode(materialPCode);
            workReport.setMaterialBCode(materialBCode);
            workReport.setWorkReportNumber(workReportNumber);
            workReport.setPoorNumber(poorNumber);
            workReports.add(workReport);
        }
        Map<String, Double> saleRepairWorkReportMap = workReports.stream().collect(Collectors.groupingBy(WorkReport::getMaterialBCode, Collectors.summingDouble(WorkReport::getQuantity)));
        return saleRepairWorkReportMap;
    }

    /**
     * 返回采购计划数量
     *
     * @return
     */
    @Override
    public Map<String, Double> fetchPurchasePlanOrder(String condition) {
        List<JSONObject> purchaseOrderList = this.logicInstanceDslService.query(condition, "PurchasePlanOrder", null);
        this.purchasePlanOrderSubs = new ArrayList<>();
        for (JSONObject jsonObject : purchaseOrderList) {
            Long orderId = jsonObject.getLong("id");
            JSONObject planValues = jsonObject.getJSONObject("values");
            String orderName = planValues.getString("name");
            String code = planValues.getString("code");
            String orderCode = planValues.getString("orderCode");
            Date startDate = planValues.getDate("startDate");
            Date endDate = planValues.getDate("endDate");
            Long mrpId = planValues.getLong("mrpId");
            Long materialId = planValues.getLong("material_id");
            String materialPCode = planValues.getString("material_pcode");
            String materialBCode = planValues.getString("material_bcode");
            String materialSpec = planValues.getString("material_spec");
            String materialModel = planValues.getString("material_model");
            Date planStartDate = planValues.getDate("startDate");
            Date planEndDate = planValues.getDate("endDate");
            Integer quantity = planValues.getInteger("quantity") == null ? 0 : planValues.getInteger("quantity");
            Boolean isLock = planValues.getBoolean("isLock");
            Boolean isCreate = planValues.getBoolean("isCreate");

            int status = planValues.getInteger("status");
            PurchasePlanOrder purchaseOrder = new PurchasePlanOrder();
            purchaseOrder.setId(orderId);
            purchaseOrder.setCode(code);
            purchaseOrder.setOrderCode(orderCode);
            purchaseOrder.setName(orderName);
            purchaseOrder.setStartDate(startDate);
            purchaseOrder.setEndDate(endDate);
            purchaseOrder.setStatus(status);
            purchaseOrder.setMrpId(mrpId);
            purchaseOrder.setMaterialId(materialId);
            purchaseOrder.setMaterialPCode(materialPCode);
            purchaseOrder.setMaterialBCode(materialBCode);
            purchaseOrder.setMaterialModel(materialModel);
            purchaseOrder.setMaterialSpec(materialSpec);
            purchaseOrder.setStartDate(planStartDate);
            purchaseOrder.setEndDate(planEndDate);
            purchaseOrder.setQuantity(quantity);
            purchaseOrder.setLocked(isLock);
            purchaseOrder.setCreated(isCreate);

            purchasePlanOrders.add(purchaseOrder);
        }
        Map<String, Double> purchaseMap = purchasePlanOrders.stream().collect(Collectors.groupingBy(PurchasePlanOrder::getMaterialBCode, Collectors.summingDouble(PurchasePlanOrder::getQuantity)));
        return purchaseMap;
    }

    /**
     * 采购订单明细在途量统计
     *
     * @param condition     主表条件
     * @param hierCondition 子表条件
     * @param className     类名
     * @return
     */
    @Override
    public Map<String, Double> fetchPurchaseOrderSub(String condition, String hierCondition, String className) {
        List<LogicInstance> logicInstances = this.logicInstanceDslService.fetchInstanceList(condition, className, null);
        List<String> containerIds = logicInstances.stream().map(LogicInstance::getId).map(m -> m + "").collect(toList());
        if (CollectionUtil.isEmpty(containerIds)) {
            return new HashMap<>();
        }
        String tempIds = String.join(",", containerIds);
        hierCondition = hierCondition + " and containerId in (" + tempIds + ")";
        List<HierInstance> purchaseOrderSubList = this.hierInstanceDslService.query(ModelType.Logic.getCode(), className, hierCondition);

        List<PurchaseOrderSub> purchaseOrderSubs = new ArrayList<>();
        for (HierInstance hIns : purchaseOrderSubList) {
            JSONObject mainValues = hIns.getValues();
            String materialPCode = mainValues.getString("material_pcode");
            String materialBCode = mainValues.getString("material_bcode");
            Integer planQuantity = mainValues.getInteger("quantity") == null ? 0 : mainValues.getInteger("quantity");
            Integer arrivalQuantity = mainValues.getInteger("arrivalQuantity") == null ? 0 : mainValues.getInteger("arrivalQuantity");
            PurchaseOrderSub purchaseOrderSub = new PurchaseOrderSub();
            purchaseOrderSub.setMaterialPCode(materialPCode);
            purchaseOrderSub.setMaterialBCode(materialBCode);
            purchaseOrderSub.setPlanQuantity(planQuantity);
            purchaseOrderSub.setArrivalQuantity(arrivalQuantity);
            purchaseOrderSubs.add(purchaseOrderSub);
        }
        Map<String, Double> purchaseOrderSubMap = purchaseOrderSubs.stream().filter(p -> StringUtils.isNotBlank(p.getMaterialBCode())).collect(Collectors.groupingBy(PurchaseOrderSub::getMaterialBCode, Collectors.summingDouble(PurchaseOrderSub::getQuantity)));
        return purchaseOrderSubMap;
    }

    /**
     * 采购订单明细合并，并返回map<物料,数量>
     *
     * @param planOrders 采购订单参数
     * @return 返回map
     */
    @Override
    public Map<String, Integer> fetchPurchasePlanOrderMap(List<PurchasePlanOrder> planOrders) {
        List<PurchasePlanOrderSub> planOrderSubs = new ArrayList<>();
        planOrders.forEach(p -> {
            List<PurchasePlanOrderSub> purchasePlanOrderSubList = p.getPurchasePlanOrderSubList();
            planOrderSubs.addAll(purchasePlanOrderSubList);
        });
        Map<String, Integer> purchaseMap = planOrderSubs.stream().collect(Collectors.groupingBy(PurchasePlanOrderSub::getMaterialBCode, Collectors.summingInt(PurchasePlanOrderSub::getQuantity)));
        return purchaseMap;
    }

    /**
     * 返回委外计划数量
     *
     * @return
     */
    @Override
    public Map<String, Double> fetchOutsourcingPlanOrder(String condition) {
        List<JSONObject> outsourcingOrderList = this.logicInstanceDslService.query(condition, "OutsourcingPlanOrder", null);
        this.outsourcingPlanOrderSubs = new ArrayList<>();
        for (JSONObject jsonObject : outsourcingOrderList) {
            Long orderId = jsonObject.getLong("id");
            JSONObject planValues = jsonObject.getJSONObject("values");

            String code = planValues.getString("code");
            String orderCode = planValues.getString("orderCode");
            String orderName = planValues.getString("name");
            String orderType = planValues.getString("orderType");
            Long materialId = planValues.getLong("material_id");
            String materialPCode = planValues.getString("material_pcode");
            String materialBCode = planValues.getString("material_bcode");
            String materialSpec = planValues.getString("material_spec");
            String materialModel = planValues.getString("material_model");
            String materialUnit = planValues.getString("material_unit");
            Date planStartDate = planValues.getDate("startDate");
            Date planEndDate = planValues.getDate("endDate");
            Integer quantity = planValues.getInteger("quantity");
            Integer status = planValues.getInteger("status");
            Long mrpId = planValues.getLong("mrpId");
            Boolean isLock = planValues.getBoolean("isLock");
            Boolean isCreate = planValues.getBoolean("isCreate");

            OutsourcingPlanOrder outsourcingOrder = new OutsourcingPlanOrder();
            outsourcingOrder.setId(orderId);
            outsourcingOrder.setCode(code);
            outsourcingOrder.setOrderCode(orderCode);
            outsourcingOrder.setName(orderName);
            outsourcingOrder.setOrderType(orderType);
            outsourcingOrder.setMaterialId(materialId);
            outsourcingOrder.setMaterialPCode(materialPCode);
            outsourcingOrder.setMaterialBCode(materialBCode);
            outsourcingOrder.setMaterialModel(materialModel);
            outsourcingOrder.setMaterialSpec(materialSpec);
            outsourcingOrder.setMaterialUnit(materialUnit);
            outsourcingOrder.setStatus(status);
            outsourcingOrder.setStartDate(planStartDate);
            outsourcingOrder.setEndDate(planEndDate);
            outsourcingOrder.setQuantity(quantity);
            outsourcingOrder.setMrpId(mrpId);
            outsourcingOrder.setLocked(isLock);
            outsourcingOrder.setCreated(isCreate);

            JSONObject hier = jsonObject.getJSONObject("hier");
            JSONArray content = hier.getJSONArray("content");
            if (content == null || content.size() < 1) {
                continue;
            }
            outsourcingOrder.setOutsourcingPlanOrderSubList(new ArrayList<>());
            for (int i = 0; i < content.size(); i++) {
                JSONObject contentJson = (JSONObject) content.get(i);
                String nodeId = contentJson.getString("nodeId");
                if (nodeId.equalsIgnoreCase("root")) {
                    continue;
                }
                JSONObject values = contentJson.getJSONObject("values");
                Long materialIdSub = values.getLong("material_id");
                String materialPCodeSub = values.getString("material_pcode");
                String materialBCodeSub = values.getString("material_bcode");
                String materialSpecSub = values.getString("material_spec");
                String materialModelSub = values.getString("material_model");
                String materialUnitSub = values.getString("material_unit");
                Integer quantitySub = values.getInteger("quantity");

                OutsourcingPlanOrderSub outsourcingOrderSub = new OutsourcingPlanOrderSub();
                outsourcingOrderSub.setOrderId(orderId);
                outsourcingOrderSub.setMaterialId(materialIdSub);
                outsourcingOrderSub.setMaterialPCode(materialPCodeSub);
                outsourcingOrderSub.setMaterialBCode(materialBCodeSub);
                outsourcingOrderSub.setMaterialModel(materialModelSub);
                outsourcingOrderSub.setMaterialSpec(materialSpecSub);
                outsourcingOrderSub.setMaterialUnit(materialUnitSub);
                outsourcingOrderSub.setQuantity(quantitySub);

                //明细合并
                this.outsourcingPlanOrderSubs.add(outsourcingOrderSub);
                outsourcingOrder.getOutsourcingPlanOrderSubList().add(outsourcingOrderSub);
            }
            this.outsourcingPlanOrders.add(outsourcingOrder);
        }
        Map<String, Double> outsourcingMap = outsourcingPlanOrders.stream().collect(Collectors.groupingBy(OutsourcingPlanOrder::getMaterialBCode, Collectors.summingDouble(OutsourcingPlanOrder::getQuantity)));
        return outsourcingMap;
    }

    @Override
    public List<OutsourcingProduct> fetchOutsourcingProduct(Long orderId) {
        List<HierInstance> hierInstances = this.hierInstanceDslService.fetchByParentId(ModelType.Logic.getCode(), "outsourcingOrder", orderId, "220hbsn5qwhs00");
        List<OutsourcingProduct> products = new ArrayList<>();
        hierInstances.forEach(hIns -> {
            Long id = hIns.getId();
            JSONObject values = hIns.getValues();
            Long materialId = values.getLong("material_id");
            String materialName = values.getString("material_name");
            String materialPCode = values.getString("material_pcode");
            String materialBCode = values.getString("material_bcode");
            String materialModel = values.getString("material_model");
            String materialSpec = values.getString("material_spec");
            String materialUnit = values.getString("material_unit");
            String materialSubUnit = values.getString("material_subUnit");
            Double quantity = values.getDouble("quantity") == null ? 0 : values.getDouble("quantity");
            Double subQuantity = values.getDouble("subQuantity") == null ? 0 : values.getDouble("subQuantity");
            Double conversionRate = values.getDouble("conversionRate") == null ? quantity : values.getDouble("conversionRate");
            Double price = values.getDouble("price") == null ? 0 : values.getDouble("price");
            Double amount = values.getDouble("amount") == null ? 0 : values.getDouble("amount");
            OutsourcingProduct product = new OutsourcingProduct();
            product.setId(id);
            product.setOrderId(orderId);
            product.setMaterialId(materialId);
            product.setMaterialName(materialName);
            product.setMaterialPCode(materialPCode);
            product.setMaterialBCode(materialBCode);
            product.setMaterialModel(materialModel);
            product.setMaterialSpec(materialSpec);
            product.setMaterialUnit(materialUnit);
            product.setMaterialSubUnit(materialSubUnit);
            product.setQuantity(quantity);
            product.setSubQuantity(subQuantity);
            product.setConversionRate(conversionRate);
            product.setPrice(price);
            product.setAmount(amount);
            products.add(product);
        });
        return products;
    }

//    @Override
//    public List<OutsourcingSubMaterial> fetchOutsourcingSubMaterial(String bCode, double quantity) {
//        String bomType = this.productBomBslService.checkProductBomType(bCode);
//        if ("combined".equalsIgnoreCase(bomType)) {
//            return fetchOutsourcingCombinedBOM(bCode, quantity);
//        } else if ("split".equalsIgnoreCase(bomType)) {
//            return fetchOutsourcingSplitBOM(bCode, quantity);
//        } else {
//            String msg = String.format("背番：%s的产品BOM没有维护，无法创建用料信息！", bCode);
//            throw new BusinessException("999999", msg);
//        }
//    }

    @Override
    public List<OutsourcingSubMaterial> fetchOutsourcingSubMaterial(String bCode, double quantity) {
        ProductBomMaster productBomMaster = this.productBomBslService.getProductBomList().stream().filter(d -> bCode.equalsIgnoreCase(d.getMaterialBCode())).findFirst().orElse(null);
        if (productBomMaster == null) {
            String msg = String.format("背番：%s的产品BOM没有维护，无法创建用料信息！", bCode);
            throw new BusinessException("999999", msg);
        }

        List<ProductBomSub> materialBomList = productBomMaster.getMaterialBomSubList();
        List<OutsourcingSubMaterial> outsourcingSubMaterials = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(materialBomList)) {
            materialBomList.forEach(mBom -> {
                Double bomQuantity = mBom.getQuantity() == null ? 0 : mBom.getQuantity();
                Double tempQuantity = quantity * bomQuantity;
                String materialPCode = mBom.getMaterialPCode();
                String materialBCode = mBom.getMaterialBCode();
                Material material = this.materialBslService.getMaterials().stream().filter(m -> m.getBcode().equalsIgnoreCase(materialBCode)).findFirst().orElse(null);
                Double conversionRate = material.getConversionRate();
                double subQuantity;
                if(conversionRate == null){
                    subQuantity = 1;
                    conversionRate = tempQuantity * 1.0;
                }else if(TypeUtils.ceilNumber(conversionRate*100)/100 > 0){
                    subQuantity = TypeUtils.ceilNumber(tempQuantity*1.0/conversionRate);
                }else{
                    throw new BusinessException("999999", String.format("背番：%s物料单位转换率为0，主数量除以转换率（0）异常，合并生成委外计划失败！",material.getBcode()));
                }
                OutsourcingSubMaterial subMaterial = new OutsourcingSubMaterial();
                subMaterial.setMaterialId(material.getId());
                subMaterial.setMaterialName(material.getName());
                subMaterial.setMaterialPCode(materialPCode);
                subMaterial.setMaterialBCode(materialBCode);
                subMaterial.setMaterialModel(material.getModel());
                subMaterial.setMaterialSpec(material.getSpec());
                subMaterial.setMaterialUnit(material.getUnit());
                subMaterial.setMaterialSubUnit(material.getSubUnit());
                subMaterial.setQuantity(tempQuantity);
                subMaterial.setSubQuantity(subQuantity);
                subMaterial.setConversionRate(conversionRate);
                subMaterial.setPrice(material.getReferToPrice());
                outsourcingSubMaterials.add(subMaterial);
            });
        }
        return outsourcingSubMaterials;
    }

//    @Override
//    public List<OutsourcingSubMaterial> fetchOutsourcingSplitBOM(String bCode, double quantity) {
//        List<OutsourcingSubMaterial> outsourcingSubMaterials = new ArrayList<>();
//        HierInstance hierInstance = this.productBomBslService.getSpitHierInstances().stream().filter(d -> d.getValues().getString("material_bcode").equalsIgnoreCase(bCode)).findFirst().orElse(null);
//        if (hierInstance != null) {
//            String parentId = hierInstance.getParentId();
//            JSONObject values = hierInstance.getValues();
//            int bomQuantity = values.getInteger("quantity");
//
//            HierInstance parentInstance = this.productBomBslService.getSpitHierInstances().stream().filter(d -> d.getNodeId().equalsIgnoreCase(parentId)).findFirst().orElse(null);
//            Double calcQuantity = Math.ceil(quantity * 1.0 / bomQuantity);
//            JSONObject parentValues = parentInstance.getValues();
//            String materialPCode = parentValues.getString("material_pcode");
//            String materialBCode = parentValues.getString("material_bcode");
//
//            Material material = this.materialBslService.getMaterials().stream().filter(m -> m.getBcode().equalsIgnoreCase(materialBCode)).findFirst().orElse(null);
//            Double conversionRate = material.getConversionRate();
//            double subQuantity;
//            if(conversionRate == null){
//                subQuantity = 1;
//                conversionRate = calcQuantity * 1.0;
//            }else if(TypeUtils.ceilNumber(conversionRate*100)/100 > 0){
//                subQuantity = TypeUtils.ceilNumber(calcQuantity*1.0/conversionRate);
//            }else{
//                throw new BusinessException("999999", String.format("背番：%s物料单位转换率为0，主数量除以转换率（0）异常，合并生成委外计划失败！",material.getBcode()));
//            }
//            OutsourcingSubMaterial subMaterial = new OutsourcingSubMaterial();
//            subMaterial.setMaterialId(material.getId());
//            subMaterial.setMaterialName(material.getName());
//            subMaterial.setMaterialPCode(materialPCode);
//            subMaterial.setMaterialBCode(materialBCode);
//            subMaterial.setMaterialModel(material.getModel());
//            subMaterial.setMaterialSpec(material.getSpec());
//            subMaterial.setMaterialUnit(material.getUnit());
//            subMaterial.setMaterialSubUnit(material.getSubUnit());
//            subMaterial.setQuantity(calcQuantity);
//            subMaterial.setSubQuantity(subQuantity);
//            subMaterial.setConversionRate(conversionRate);
//            subMaterial.setPrice(material.getReferToPrice());
//            outsourcingSubMaterials.add(subMaterial);
//        }
//        return outsourcingSubMaterials;
//    }

    /**
     * 委外订单明细在途量统计
     *
     * @param condition     主表条件
     * @param hierCondition 子表条件
     * @param className     类名
     * @return
     */
    @Override
    public Map<String, Double> fetchOutsourcingOrderSub(String condition, String hierCondition, String className) {
        List<LogicInstance> logicInstances = this.logicInstanceDslService.fetchInstanceList(condition, className, null);
        List<String> containerIds = logicInstances.stream().map(LogicInstance::getId).map(m -> m + "").collect(toList());
        if (CollectionUtil.isEmpty(containerIds)) {
            return new HashMap<>();
        }
        String tempIds = String.join(",", containerIds);
        hierCondition = hierCondition + " and containerId in (" + tempIds + ")";
        List<HierInstance> purchaseOrderSubList = this.hierInstanceDslService.query(ModelType.Logic.getCode(), className, hierCondition);

        List<OutsourcingOrderSub> outsourcingOrderSubs = new ArrayList<>();
        for (HierInstance hIns : purchaseOrderSubList) {
            JSONObject mainValues = hIns.getValues();
            String materialPCode = mainValues.getString("material_pcode");
            String materialBCode = mainValues.getString("material_bcode");
            Integer planQuantity = mainValues.getInteger("quantity") == null ? 0 : mainValues.getInteger("quantity");
            Integer arrivalQuantity = mainValues.getInteger("arrivalQuantity") == null ? 0 : mainValues.getInteger("arrivalQuantity");
            OutsourcingOrderSub outsourcingOrderSub = new OutsourcingOrderSub();
            outsourcingOrderSub.setMaterialPCode(materialPCode);
            outsourcingOrderSub.setMaterialBCode(materialBCode);
            outsourcingOrderSub.setPlanQuantity(planQuantity);
            outsourcingOrderSub.setArrivalQuantity(arrivalQuantity);
            outsourcingOrderSubs.add(outsourcingOrderSub);
        }
        Map<String, Double> outsourcingOrderSubMap = outsourcingOrderSubs.stream().collect(Collectors.groupingBy(OutsourcingOrderSub::getMaterialBCode, Collectors.summingDouble(OutsourcingOrderSub::getQuantity)));
        return outsourcingOrderSubMap;
    }

    /**
     * 采购订单明细合并，并返回map<物料,数量>
     *
     * @param planOrders 采购订单参数
     * @return 返回map
     */
    @Override
    public Map<String, Integer> fetchProductionPlanOrderMap(List<ProductionPlanOrder> planOrders, List<ProductionPlanOrderSub> planOrderSubs) {
        planOrders.forEach(p -> {
            List<ProductionPlanOrderSub> productionPlanOrderSubList = p.getProductionPlanOrderSubList();
            planOrderSubs.addAll(productionPlanOrderSubList);
        });
        Map<String, Integer> purchaseMap = planOrderSubs.stream().collect(Collectors.groupingBy(ProductionPlanOrderSub::getMaterialBCode, Collectors.summingInt(ProductionPlanOrderSub::getQuantity)));
        return purchaseMap;
    }

}
